﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;
using System.Text.Json;

namespace Masa.Blazor.SourceGenerator;

[Generator]
public class JSManifestGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var manifestFiles = context.AdditionalTextsProvider
            .Where(file => file.Path.EndsWith("manifest.json"));

        var manifestContent = manifestFiles
            .Select((file, cancellationToken) =>
            {
                var text = file.GetText(cancellationToken);
                return text?.ToString();
            });

        context.RegisterSourceOutput(manifestContent.Collect(),
            (spc, contents) =>
            {
                foreach (var content in contents)
                {
                    if (content == null) continue;

                    try
                    {
                        var manifest = JsonSerializer.Deserialize<Dictionary<string, string>>(content);
                        var code = GenerateManifestClass(manifest);
                        spc.AddSource("JSManifest.g.cs", SourceText.From(code, Encoding.UTF8));
                    }
                    catch (JsonException ex)
                    {
                        // 报告 JSON 解析错误
                        spc.ReportDiagnostic(Diagnostic.Create(
                            new DiagnosticDescriptor(
                                "JSMANIFEST001",
                                "Invalid manifest.json",
                                $"JSON parsing error: {ex.Message}",
                                "Build",
                                DiagnosticSeverity.Error,
                                true),
                            Location.None));
                    }
                }
            });
    }

    private string GenerateManifestClass(Dictionary<string, string> manifest)
    {
        var sb = new StringBuilder();
        sb.AppendLine("// <auto-generated/>");
        sb.AppendLine("#pragma warning disable CS1591");
        sb.AppendLine("namespace Masa.Blazor.SourceGenerated;");
        sb.AppendLine("public static class JSManifest");
        sb.AppendLine("{");

        foreach (var entry in manifest)
        {
            var key = SanitizeIdentifier(entry.Key);
            sb.AppendLine($"    public const string {key} = \"{entry.Value}\";");
        }

        sb.AppendLine("}");
        return sb.ToString();
    }

    private static string SanitizeIdentifier(string key)
    {
        if (key.StartsWith("components/") || key.StartsWith("mixins/") || key.StartsWith("proxies/"))
        {
            key = key[(key.IndexOf('/') + 1)..];
        }

        var sanitized = new StringBuilder();
        var nextUpper = true;

        foreach (var c in key)
        {
            if (char.IsLetterOrDigit(c))
            {
                sanitized.Append(nextUpper ? char.ToUpper(c) : c);
                nextUpper = false;
            }
            else
            {
                nextUpper = true;
            }
        }

        return sanitized.ToString();
    }
}